#include "common.h"

void die(const char *reason)
{
  fprintf(stderr, "%s\n", reason);
  exit(EXIT_FAILURE);
}

/**
 * [read_config description]    读取节点信息的配置文件
 * @param  fname [description]  配置文件
 * @return       [description]  节点的信息
 */
DataNode* read_config_Node(const char *fname){
	printf("read_config_Node begin............................\n");
	DataNode* nodes = NULL;
	FILE *fp = fopen(fname,"r");
	if(!fp) return nodes;

	nodes =(DataNode*) malloc(DATANODE_NUM*sizeof(DataNode));
	char strbuf[512]={'\0'};
	//配置数据节点 保持下标与nodeID一致便于查询
	int i;
	for(i=0;i<DATANODE_NUM&&!feof(fp);i++){
        while(fgets(strbuf,sizeof(strbuf),fp) && strbuf[0]==COMMENTS);
    	sscanf(strbuf,"%s%s%d",nodes[i].tcp_ip,nodes[i].rdma_ip,&nodes[i].nodeID);
    }

	return nodes;
}

/**
 * [get_ipaddr description]  获取本机的IP地址
 * @param ip  [description]  
 * @param len [description]
 */
void get_ipaddr(char *ip,int len){
    printf("get_ipaddr begin......................................\n");
    int i=0,sockfd=-1,tlen;
    if(!ip || len<16)return;
    struct sockaddr_in *sip;
    struct ifreq *irp;
    struct ifconf ic;
    char buf[512],*iptemp,ethstr[4]={'\0'};
    ic.ifc_len = 512;
    ic.ifc_buf = buf;
    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    ioctl(sockfd, SIOCGIFCONF, &ic);
    irp = (struct ifreq*)buf;
    for(i=(ic.ifc_len/sizeof(struct ifreq)); i>0; i--,irp++){
        sip=(struct sockaddr_in*)&(irp->ifr_addr);
        iptemp=inet_ntoa(sip->sin_addr);
        tlen=1+strlen(iptemp);
        memcpy(ethstr,irp->ifr_name,3);
        if(0==strcmp(ETH,ethstr)){
            if(len >= tlen)strncpy(ip,iptemp,tlen);
            break;
        }
    }
    close(sockfd);
}

/**
 * [current_node description]  获取当前节点编号
 * @param  p [description]
 * @return   [description]    当前节点编号 
 */
int current_node(DataNode* nodes){
    printf("current_node begin................................\n");
    char ip[17];
    if(!nodes)return -1;
    get_ipaddr(ip,16);
    int i;
    for(i=0;i<DATANODE_NUM;i++){
    if(strcmp(ip,nodes[i].tcp_ip)==0) return nodes[i].nodeID; //比较ip地址是否相同 相同的话返回节点编号
    }
    return -1;
}

/**
*  根据sockaddr addr在加载的nodes信息里面查找
*  返回 nodeid，如果为查找到，返回-1
*/
int get_nodeid(struct sockaddr* addr,DataNode* nodes){
    struct sockaddr_in *sock = (struct sockaddr_in*)addr;
    struct in_addr in = sock->sin_addr;
    char str[16];
    inet_ntop(AF_INET,&in,str,sizeof(str));
    //printf("%s\n",str);
    for (int i = 0; i < DATANODE_NUM; i++)
    {
      //printf("%s\n",nodes[i].rdma_ip);
      if(strcmp(str,nodes[i].rdma_ip)==0) return i;
    }
    return -1;
}


/**
 * [connect_try description]   client尝试连接server
 * @param  ip   [description]  服务端ip 地址
 * @param  port [description]  服务端端口号
 * @return      [description]  返回套接字sockfd
 */
int connect_try(char *ip,unsigned short port){//支持重连接
    printf("connect_try begin..................................\n");
    int nsec,sockfd;
    //struct linger lg={1,5};
    struct sockaddr_in sa;   //地址
    sa.sin_family = AF_INET;
    sa.sin_port = htons(port);
    sa.sin_addr.s_addr=inet_addr(ip);

    sockfd=socket(AF_INET,SOCK_STREAM,0);  //socket 套接字

    if((-1 != sockfd))
    {
        for(nsec=1;nsec <= Max_Wait;nsec++)
        {
            if(0 == connect(sockfd,(struct sockaddr *)&sa,sizeof(sa))){  //客户端建立连接，若成功返回0，若出错返回-1

            int sendsize = 51200000;
            int svcsize=51200000;
            if(setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, (char*)&sendsize, sizeof(sendsize)) < 0){//设置发送缓冲区大小
            perror("setsockopt");
            exit(1);
            }
            if(setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (char*)&svcsize, sizeof(svcsize)) < 0){ //设置接收缓冲区大小
            perror("setsockopt");
            exit(1);
            }
            int flag = 1;   
            if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *)&flag, sizeof(int)) < 0){//设置端口复用
            perror("setsockopt");
            exit(1);
            }
            if(setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int)) < 0){//屏蔽Nagle算法，避免不可预测的延迟
            perror("setsockopt");
            exit(1);
            }
             
            printf("connect %s succeed\n", ip);  //连接成功
            return sockfd;//连接Server 
            }
            printf("connect_try %s sleep ........\n",ip);
            if(nsec <= Max_Wait) sleep(1);
        }
        close(sockfd);
    }
    return -1;
}

/**
 * [server_bind description]      服务端建立连接  server
  * @param  port    [description]   服务端端口号
 *  @param  backlog [description]   socket可排队的最大连接个数
 *  @return         [description]    通信套接字
 */
int server_bind(unsigned short port,int backlog){
    printf("server_bind begin .........................................\n");
    int listen_sock;//创建监听套接字
    int opt = SO_REUSEADDR;

    struct sockaddr_in sa;  //地址
    socklen_t slen = sizeof(sa);  //协议地址的长度
    sa.sin_family = AF_INET;
    sa.sin_addr.s_addr = htonl(INADDR_ANY);
    sa.sin_port = htons(port);

    listen_sock=socket(AF_INET, SOCK_STREAM, 0); //套接字建立域  套接字类型 0

    setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));//SO_REUSEADDR 仅仅表示可以重用本地本地地址、本地端口
    
    bind(listen_sock, (struct sockaddr *)&sa, sizeof(sa));  //将套接字与地址绑定  套接字  地址 地址长度
   
   //服务端监听 成功返回0  出错返回-1 。c语言规定，任何非0的数像1 -1等都被认为是真，而0被认为是假
    if (listen(listen_sock, backlog)<0){  
        printf("portListen ~ listen() error.\n");
        return -1;
    }

    return listen_sock;
}


int server_accept(int listen_sock){
    int connect_sock;//创建通信套接字
    struct sockaddr_in sa;  //地址
    socklen_t slen = sizeof(sa);  //协议地址的长度
    while (1){
        connect_sock = accept(listen_sock, (struct sockaddr *)&sa, &slen);  //通信套接字 成功返回套接字 出错返回-1
        if (-1 == connect_sock){
            printf("portListen ~ accept() error.\n");
        }else{
            printf("server_accept made .client ip ：%s connect to local.\n", inet_ntoa(sa.sin_addr));
            break;
        }
    }

    int sendsize=512000;
    int svcsize=512000;

    if(setsockopt(connect_sock, SOL_SOCKET, SO_RCVBUF, (char*)&sendsize, sizeof(sendsize)) < 0){//设置发送缓冲区大小
        perror("setsockopt");
        exit(1);
    }
    if(setsockopt(connect_sock, SOL_SOCKET, SO_SNDBUF, (char*)&svcsize, sizeof(svcsize)) < 0){ //设置接收缓冲区大小
        perror("setsockopt");
        exit(1);
    }
    int flag = 1;   
    if(setsockopt(connect_sock, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(int)) < 0){//设置端口复用
        perror("setsockopt");
        exit(1);
    }
    if(setsockopt(connect_sock, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int)) < 0){//屏蔽Nagle算法，避免不可预测的延迟
        perror("setsockopt");
        exit(1);
    }
    return connect_sock;  //返回通信套接字  成功返回套接字 出错返回-1
}

/**
 * [send_bytes description]       一次性发送文件
 * @param  sockfd [description]   套接字
 * @param  buf    [description]   缓冲区
 * @param  nbytes [description]   字节大小
 * @return        [description]   总的发送文件大小
 */
ssize_t send_bytes(int sockfd,char *buf,size_t nbytes){
    size_t total=0;
    int once;
    for(once=0;total<nbytes;total+=once){
        //printf("222\n");
        once=send(sockfd,buf+total,nbytes-total,0);
        //printf("333\n");
        if(once<=0) break;
    }
    return total;
}


/**
 * [recv_bytes description]      一次性接收文件
 * @param  sockfd [description]
 * @param  buf    [description]
 * @param  nbytes [description]
 * @return        [description]
 */
ssize_t recv_bytes(int sockfd,char *buf,size_t nbytes){
    size_t total=0;
    int once;
    for(once=0;total<nbytes;total+=once){
        once=recv(sockfd,buf+total,nbytes-total,0);
        //printf("recv_bytes_once:%d\n", once);
        if(once<=0)break;
    }
    //printf("recv_bytes_total:%d\n", total);
    return total;
}

void new_strtok(char string[],char divider,char result[])
{
    int i,j;

    for (i = 0;string[i]!='\0';i++)
    {
        if (string[i]!=divider)
            result[i]=string[i];
        else
            break;
    }

    if (string[i]=='\0')
    {
        result[i]='\0';
    }else{
        result[i]='\0';
        for (j = 0;string[j]!='\0'; j++)
        {
            string[j]=string[j+i+1];
        }
    }
}

void trnsfm_char_to_int(char* char_data,long long *data)
{
    int i=0;
    *data=0LL;

    while(char_data[i]!='\0'){
        if(char_data[i]>='0'&&char_data[i]<='9'){
            (*data)*=10;
            (*data)+=char_data[i]-'0';
        }
        i++;
    }
}

void gene_radm_buff(char* buff,int len)
{
    int i;
    char alphanum[]="0123456789ABCDEFGHIJKLMEOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
    for(i=0;i<BLK_SIZE;i++)
        buff[i] = alphanum[i%(sizeof(alphanum)-1)]; 
}

char* convert_id_to_string(long long id){
    char* res=(char*)malloc(sizeof(char)*30);
    memset(res,'\0',30);
    sprintf(res, "%lld", id);
    return res;
}

char* convert_int_to_string(int src){
    char* res =(char*)malloc(30);
    memset(res,'\0',30);
    sprintf(res, "%d", src);
    return res;
}

long getcurrent_time(){
    struct timeval time_now = {0};
    long time_mic = 0;
    gettimeofday(&time_now,NULL);
    time_mic = time_now.tv_sec*1000*1000+time_now.tv_usec;
    return time_mic;
}